package com.hanlp.utils;

import com.hanlp.bean.*;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 东方财富API统一工具类
 * 整合股票和可转债功能，提供统一的数据获取接口
 */
public class EastMoneyApiUtil {

    /**
     * 构建股票代码（带市场前缀）
     *
     * @param marketCode 市场代码（0:深圳, 1:上海）
     * @param stockCode  股票代码
     * @return 完整的股票代码
     */
    public static String buildStockCode(String marketCode, String stockCode) {
        return marketCode + "." + stockCode;
    }

    /**
     * 自动识别股票市场并构建代码
     *
     * @param stockCode 股票代码
     * @return 完整的股票代码
     */
    public static String buildStockCodeAuto(String stockCode) {
        if (stockCode.startsWith("6")) {
            // 上海A股
            return MarketCode.SHANGHAI + "." + stockCode;
        } else if (stockCode.startsWith("0") || stockCode.startsWith("3")) {
            // 深圳A股（主板、中小板、创业板）
            return MarketCode.SHENZHEN + "." + stockCode;
        } else {
            // 默认深圳
            return MarketCode.SHENZHEN + "." + stockCode;
        }
    }

    /**
     * 获取当前日期字符串（用于K线查询）
     *
     * @return 格式为yyyyMMdd的日期字符串
     */
    public static String getCurrentDateString() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    /**
     * 获取指定天数前的日期字符串
     *
     * @param daysBefore 天数
     * @return 格式为yyyyMMdd的日期字符串
     */
    public static String getDateStringBefore(int daysBefore) {
        return LocalDate.now().minusDays(daysBefore).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    /**
     * 获取多只股票的实时行情
     *
     * @param stockCodes 股票代码数组（不带市场前缀）
     * @param delayMs    请求间隔毫秒数
     * @return 行情数据数组
     */
    public static String[] getMultiStockRealTime(String[] stockCodes, long delayMs) {
        String[] secids = new String[stockCodes.length];
        for (int i = 0; i < stockCodes.length; i++) {
            secids[i] = buildStockCodeAuto(stockCodes[i]);
        }
        return EastMoneyStockUtil.batchGetStockData(secids, delayMs);
    }

    /**
     * 获取多只股票的实时行情Bean对象
     *
     * @param stockCodes 股票代码数组（不带市场前缀）
     * @param delayMs    请求间隔毫秒数
     * @return ApiResponse<List<StockRealTimeData>>对象
     */
    public static ApiResponse<List<StockRealTimeData>> getMultiStockRealTimeBean(String[] stockCodes, long delayMs) {
        try {
            String[] results = getMultiStockRealTime(stockCodes, delayMs);
            // 这里需要进一步处理批量数据的解析
            // 暂时返回错误，需要根据实际API响应格式调整
            return ApiResponse.error("批量股票数据解析功能待完善");
        } catch (Exception e) {
            return ApiResponse.error("获取股票实时行情失败: " + e.getMessage());
        }
    }

    /**
     * 获取多只可转债的实时行情
     *
     * @param bondCodes 可转债代码数组（不带市场前缀）
     * @param delayMs   请求间隔毫秒数
     * @return 行情数据数组
     */
    public static String[] getMultiBondRealTime(String[] bondCodes, long delayMs) {
        String[] secids = new String[bondCodes.length];
        for (int i = 0; i < bondCodes.length; i++) {
            // 可转债通常在深圳市场
            secids[i] = MarketCode.SHENZHEN + "." + bondCodes[i];
        }
        return EastMoneyBondUtil.batchGetConvertibleBondData(secids, delayMs);
    }

    /**
     * 获取股票近期K线数据（最近N个交易日）
     *
     * @param stockCode 股票代码（不带市场前缀）
     * @param days      天数
     * @param klineType K线类型（101:日K, 102:周K, 103:月K）
     * @return JSON格式的K线数据
     * @throws IOException 网络请求异常
     */
    public static String getStockRecentKLine(String stockCode, int days, int klineType) throws IOException {
        String secid = buildStockCodeAuto(stockCode);
        String endDate = getCurrentDateString();
        String startDate = getDateStringBefore(days);
        return EastMoneyStockUtil.getKLineData(secid, klineType, 0, startDate, endDate);
    }

    /**
     * 获取股票近期K线数据Bean对象（最近N个交易日）
     *
     * @param stockCode 股票代码（不带市场前缀）
     * @param days      天数
     * @param klineType K线类型（101:日K, 102:周K, 103:月K）
     * @return KLineData对象
     * @throws IOException 网络请求异常
     */
    public static KLineData getStockRecentKLineBean(String stockCode, int days, int klineType) throws IOException {
        String jsonResponse = getStockRecentKLine(stockCode, days, klineType);
        return JsonUtil.parseKLineData(jsonResponse);
    }

    /**
     * 获取可转债近期K线数据（最近N个交易日）
     *
     * @param bondCode  可转债代码（不带市场前缀）
     * @param days      天数
     * @param klineType K线类型（101:日K, 102:周K, 103:月K）
     * @return JSON格式的K线数据
     * @throws IOException 网络请求异常
     */
    public static String getBondRecentKLine(String bondCode, int days, int klineType) throws IOException {
        // 可转债通常在上海市场，先尝试上海市场
        String secid = MarketCode.SHANGHAI + "." + bondCode;
        String endDate = getCurrentDateString();
        String startDate = getDateStringBefore(days);
        
        String response = EastMoneyBondUtil.getConvertibleBondKLine(secid, klineType, 0, startDate, endDate);
        
        // 如果上海市场没有数据，尝试深圳市场
        if (response.contains("\"data\":null")) {
            secid = MarketCode.SHENZHEN + "." + bondCode;
            response = EastMoneyBondUtil.getConvertibleBondKLine(secid, klineType, 0, startDate, endDate);
        }
        
        return response;
    }

    /**
     * 获取可转债近期K线数据Bean对象（最近N个交易日）
     *
     * @param bondCode  可转债代码（不带市场前缀）
     * @param days      天数
     * @param klineType K线类型（101:日K, 102:周K, 103:月K）
     * @return KLineData对象
     * @throws IOException 网络请求异常
     */
    public static KLineData getBondRecentKLineBean(String bondCode, int days, int klineType) throws IOException {
        String jsonResponse = getBondRecentKLine(bondCode, days, klineType);
        return JsonUtil.parseKLineData(jsonResponse);
    }


    /**
     * 获取主要指数实时数据
     *
     * @return JSON格式的指数数据
     * @throws IOException 网络请求异常
     */
    public static String getMajorIndexData() throws IOException {
        String indexCodes = String.join(",",
                IndexCode.SH_INDEX,
                IndexCode.SZ_INDEX,
                IndexCode.CYB_INDEX,
                IndexCode.HS300_INDEX,
                IndexCode.ZZ500_INDEX,
                IndexCode.KC50_INDEX
        );
        return EastMoneyStockUtil.getIndexData(indexCodes);
    }

    /**
     * 获取主要指数实时数据Bean对象
     *
     * @return ApiResponse<List<IndexData>>对象
     * @throws IOException 网络请求异常
     */
    public static ApiResponse<List<IndexData>> getMajorIndexDataBean() throws IOException {
        String jsonResponse = getMajorIndexData();
        return JsonUtil.parseIndexData(jsonResponse);
    }

    /**
     * 获取涨幅榜前N名股票
     *
     * @param topN 前N名
     * @return 涨幅榜数据
     * @throws IOException 网络请求异常
     */
    public static String getTopGainersStock(int topN) throws IOException {
        return EastMoneyStockUtil.getStockList(1, topN, SortField.CHANGE_PERCENT, 0);
    }

    /**
     * 获取涨幅榜前N名股票Bean对象
     *
     * @param topN 前N名
     * @return ApiResponse<List<StockRealTimeData>>对象
     * @throws IOException 网络请求异常
     */
    public static ApiResponse<List<StockRealTimeData>> getTopGainersStockBean(int topN) throws IOException {
        String jsonResponse = getTopGainersStock(topN);
        return JsonUtil.parseStockList(jsonResponse);
    }


    /**
     * 获取跌幅榜前N名股票
     *
     * @param topN 前N名
     * @return 跌幅榜数据
     * @throws IOException 网络请求异常
     */
    public static String getTopLosersStock(int topN) throws IOException {
        return EastMoneyStockUtil.getStockList(1, topN, SortField.CHANGE_PERCENT, 1);
    }


    /**
     * 获取涨幅榜前N名可转债
     *
     * @param topN 前N名
     * @return 涨幅榜数据
     * @throws IOException 网络请求异常
     */
    public static String getTopGainersBond(int topN) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondList(1, topN, SortField.CHANGE_PERCENT, 0);
    }


    /**
     * 获取跌幅榜前N名可转债
     *
     * @param topN 前N名
     * @return 跌幅榜数据
     * @throws IOException 网络请求异常
     */
    public static String getTopLosersBond(int topN) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondList(1, topN, SortField.CHANGE_PERCENT, 1);
    }


    /**
     * 获取成交量排行榜前N名股票
     *
     * @param topN 前N名
     * @return 成交量排行数据
     * @throws IOException 网络请求异常
     */
    public static String getTopVolumeStock(int topN) throws IOException {
        return EastMoneyStockUtil.getStockList(1, topN, SortField.VOLUME, 0);
    }


    /**
     * 获取成交量排行榜前N名可转债
     *
     * @param topN 前N名
     * @return 成交量排行数据
     * @throws IOException 网络请求异常
     */
    public static String getTopVolumeBond(int topN) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondList(1, topN, SortField.VOLUME, 0);
    }



    /**
     * 获取成交额排行榜前N名股票
     *
     * @param topN 前N名
     * @return 成交额排行数据
     * @throws IOException 网络请求异常
     */
    public static String getTopAmountStock(int topN) throws IOException {
        return EastMoneyStockUtil.getStockList(1, topN, SortField.AMOUNT, 0);
    }

    

    /**
     * 获取成交额排行榜前N名可转债
     *
     * @param topN 前N名
     * @return 成交额排行数据
     * @throws IOException 网络请求异常
     */
    public static String getTopAmountBond(int topN) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondList(1, topN, SortField.AMOUNT, 0);
    }


    /**
     * 获取行业板块排行
     *
     * @param topN 前N名
     * @return 行业板块数据
     * @throws IOException 网络请求异常
     */
    public static String getIndustryRanking(int topN) throws IOException {
        return EastMoneyStockUtil.getBlockData("industry", 1, topN);
    }

    /**
     * 获取行业板块排行Bean对象
     *
     * @param topN 前N名
     * @return ApiResponse<List<BlockData>>对象
     * @throws IOException 网络请求异常
     */
    public static ApiResponse<List<BlockData>> getIndustryRankingBean(int topN) throws IOException {
        String jsonResponse = getIndustryRanking(topN);
        return JsonUtil.parseBlockData(jsonResponse);
    }


    /**
     * 获取概念板块排行
     *
     * @param topN 前N名
     * @return 概念板块数据
     * @throws IOException 网络请求异常
     */
    public static String getConceptRanking(int topN) throws IOException {
        return EastMoneyStockUtil.getBlockData("concept", 1, topN);
    }

    /**
     * 获取概念板块排行Bean对象
     *
     * @param topN 前N名
     * @return ApiResponse<List<BlockData>>对象
     * @throws IOException 网络请求异常
     */
    public static ApiResponse<List<BlockData>> getConceptRankingBean(int topN) throws IOException {
        String jsonResponse = getConceptRanking(topN);
        return JsonUtil.parseBlockData(jsonResponse);
    }

   
    /**
     * 获取低溢价率可转债（溢价率小于指定值）
     *
     * @param maxPremium 最大溢价率
     * @param pageSize   返回数量
     * @return 低溢价率可转债数据
     * @throws IOException 网络请求异常
     */
    public static String getLowPremiumBonds(double maxPremium, int pageSize) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondByPremium(0, maxPremium, 1, pageSize);
    }

    

    /**
     * 获取短期可转债（剩余年限小于指定值）
     *
     * @param maxYear  最大剩余年限
     * @param pageSize 返回数量
     * @return 短期可转债数据
     * @throws IOException 网络请求异常
     */
    public static String getShortTermBonds(double maxYear, int pageSize) throws IOException {
        return EastMoneyBondUtil.getConvertibleBondByRemainYear(0, maxYear, 1, pageSize);
    }

    

    /**
     * 数据解析辅助方法：检查响应是否成功
     *
     * @param jsonResponse JSON响应字符串
     * @return 是否成功
     */
    public static boolean isResponseSuccess(String jsonResponse) {
        return jsonResponse != null &&
                !jsonResponse.contains("error") &&
                !jsonResponse.trim().isEmpty() &&
                jsonResponse.contains("data");
    }


    /**
     * 安全的数据获取方法，包含重试机制
     *
     * @param supplier     数据获取函数
     * @param maxRetries   最大重试次数
     * @param retryDelayMs 重试间隔毫秒数
     * @return 数据或错误信息
     */
    public static String safeGetData(DataSupplier supplier, int maxRetries, long retryDelayMs) {
        for (int i = 0; i <= maxRetries; i++) {
            try {
                String result = supplier.get();
                if (isResponseSuccess(result)) {
                    return result;
                }
            } catch (Exception e) {
                if (i == maxRetries) {
                    return "{\"error\":\"" + e.getMessage() + "\"}";
                }
            }

            if (i < maxRetries) {
                HttpUtil.sleep(retryDelayMs);
            }
        }

        return "{\"error\":\"获取数据失败，已达到最大重试次数\"}";
    }


    /**
     * 数据获取函数接口
     */
    @FunctionalInterface
    public interface DataSupplier {
        String get() throws IOException;
    }



    // 市场代码常量
    public static class MarketCode {
        public static final String SHENZHEN = "0";  // 深圳市场
        public static final String SHANGHAI = "1";   // 上海市场
        public static final String US = "116";       // 美股
        public static final String HK = "100";       // 港股
    }

    // 常用指数代码
    public static class IndexCode {
        public static final String SH_INDEX = "1.000001";    // 上证指数
        public static final String SZ_INDEX = "0.399001";    // 深证成指
        public static final String CYB_INDEX = "0.399006";   // 创业板指
        public static final String HS300_INDEX = "1.000300"; // 沪深300
        public static final String ZZ500_INDEX = "1.000905"; // 中证500
        public static final String KC50_INDEX = "1.000688";  // 科创50
    }

    // 排序字段常量
    public static class SortField {
        public static final String CHANGE_PERCENT = "f3";     // 涨跌幅
        public static final String PRICE = "f2";             // 最新价
        public static final String VOLUME = "f5";            // 成交量
        public static final String AMOUNT = "f6";            // 成交额
        public static final String TURNOVER_RATE = "f8";     // 换手率
        public static final String PE_RATIO = "f9";          // 市盈率
        public static final String PB_RATIO = "f23";         // 市净率
    }
}